package threads;


import execution.Manager;
import gui.WindowMain;
import gui.WindowMineResults;

import java.util.ArrayList;
import java.util.List;

import resources.Settings;
import resultsDatabase.Field;
import resultsDatabase.ListOfResults;

public class MineThread extends Thread {
	private ArrayList<Field> selectedFields = new ArrayList<Field>();
	private WindowMain window;
	private WindowMineResults windowResults;
	private boolean pause = false;
	private boolean canceled = false;
	@SuppressWarnings("unused")
	private long setsMined;
	@SuppressWarnings("unused")
	private long totalSets;
	private Manager manager;
	// create the thread list
	private List<SetGeneratorAndMiner> threads = new ArrayList<SetGeneratorAndMiner>();
	public MineThread(ArrayList<Field> values, WindowMain w, WindowMineResults wr, Manager m) {
		window=w;
		windowResults=wr;
		for (Field f : values) {
			selectedFields.add(f);
		}
		manager=m;
	}

	public void run() {
		//check if the results list is empty
		if (!ListOfResults.getInstance().getResultsList().isEmpty()){
			ListOfResults.getInstance().reset();	
		}
		// generate sets
		generateSetsAndMine();
		//change the gui on completion
		if (canceled) guiChangesCanceled();
		else guiChangesDone();
		

	}
	
	public void stopThreads(){
		canceled = true;
		for (int i = 0; i < threads.size(); i++) {
			threads.get(i).noGo();
		}
	}
	
	
	public boolean areThreadsPaused(){
		return pause;
	}
	public void pauseThreads(){
			if (pause) {
				pause=false;
				window.addStatusMessage("Mining.. ( " + selectedFields.size() + " Fields )");
			}
			else if (!pause) {
				pause=true;
				//set the progress bar
				window.addStatusMessage("Mine has been paused.");
			}
			 for (int i = 0; i < threads.size(); i++) {
					threads.get(i).pauseToggle();
				}
	}
	
	private void generateSetsAndMine() {

		// find all the possible sets between the selected fields
		// start finding the sets

		// get the number of elements in the set
		int elements = selectedFields.size();

		// the number of members of a power set is 2^n
		int powerElements = (int) Math.pow(2, elements);
		totalSets=powerElements;
		window.addStatusMessage("Mining.. ( " + selectedFields.size() + " Fields )");
		window.progressBar.setEnabled(true);
		window.progressBar.setVisible(true);
		window.progressBar.setFocusable(true);
		window.progressBar.setValue(0);
		window.progressBar.setMaximum(powerElements);
		manager.updateTotalSetsToMine(powerElements);
		// divide the amount of work in n threads
		int numOfThreads = Settings.getInstance().getCpuCores();
		//each core is estimated to handle 2 threads!
		int elementsNum[] = new int[numOfThreads+1];
		//start
		elementsNum[0]=0;
		int value = powerElements/numOfThreads;
		//middle points
		for (int i=1;i<numOfThreads;i++){
			elementsNum[i]=value*i; 
		}
		//end
		elementsNum[numOfThreads]=powerElements;
		//create the threads, and start them
		for (int i=0;i<numOfThreads;i++){
			SetGeneratorAndMiner generator = new SetGeneratorAndMiner(elementsNum[i],
					elementsNum[i+1], elements, selectedFields, window,windowResults,manager);
			generator.setName("Thread "+(i+1));
			generator.start();
			threads.add(generator);
		}
		
		
		// all threads are now started
		// later...
		window.menuMinedState();
		for (int i = 0; i < threads.size(); i++){
			try {
				((Thread) threads.get(i)).join();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
	
	private void guiChangesDone(){
		windowResults.disableStopMiningButton();
		windowResults.disablePauseMiningButton();
		window.progressBar.setEnabled(false);
		window.progressBar.setVisible(false);
		window.addStatusMessage("Mining has been completed!");
		
	}
	
	private void guiChangesCanceled(){
		windowResults.disableStopMiningButton();
		windowResults.disablePauseMiningButton();
		window.progressBar.setEnabled(false);
		window.progressBar.setVisible(false);
		window.addStatusMessage("Mining has been canceled!");
		
	}
}
